﻿/* $RCSFile: SPLA.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/CRMWrapper3/Authentication/SPLA.cs $
 * $log$
 * Revision 19 2011/01/31 15:22:05  christian.surieux
 *   Move to neutronstar
 * Revision 6 2010/08/06 19:56:32  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Services.Protocols;
using System.Web.Configuration;
using System.Web;
using System.Globalization;

using AddonNice.Security;
using AddonNice.Settings;
using AddonNice.CRMWrapper;
using AddonNice.CRMWrapper.CRM4ADDisco;
using AddonNice.CRMWrapper.CRM4Server;

namespace AddonNice.CRMWrapper.Authentication
{
	public class SPLA : CrmAuthenticationBase
	{
		protected string _adminCrmTicket                    =   string.Empty;
		public string adminCrmTicket
		{
			get
			{
				if ( _adminCrmTicket == string.Empty )
					_adminCrmTicket    =   RetrieveCrmTicket(CRMServiceDomain,CRMServiceAccount,CRMServicePassword,ref _adminCrmTicketExpirationDate);
				return _adminCrmTicket;
			}
		}

		protected string _adminCrmTicketExpirationDate      =   string.Empty;
		public string adminCrmTicketExpirationDate
		{
			get
			{
				return _adminCrmTicketExpirationDate;
			}
		}


		protected string _userCrmTicket                     =   string.Empty;
		/// <summary>
		/// Mode SPLA ticket used for the userService
		/// Addon Nice authentication mode is necessarely forms, depends on:
		/// - if user authenticated, new credentials will be created from the current authenticated user, see AddonNiceIdentity
		/// - if not authenticated (anonymous), new credentials will be used from default crm user set in web.config
		/// </summary>
		public string userCrmTicket
		{
			get
			{
				if (_userCrmTicket == string.Empty)
				{
					if ( CRMTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( "[V]SPLA userCrmTicket GET BEG.",CRMTraceSwitch.Sw.Info);
					try
					{
						AuthenticationMode auth	        =	Config.AuthenticationMode;
						if ( CRMTraceSwitch.Sw.TraceVerbose )
							Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA userCrmTicket authenticationMode: {0}", auth),CRMTraceSwitch.Sw.Info);
						if ( auth != AuthenticationMode.Forms )
						{
							throw new CRMWrapperException("Addon Nice is in Windows authentication, this is not valid for SPLA");
						}
						// Authentication == Forms
						if (HttpContext.Current.Request.IsAuthenticated 
							&& ( HttpContext.Current.User.Identity is AddonNiceIdentity ))// <- when in first setup we could have a FormIdentity
						{
							if ( CRMTraceSwitch.Sw.TraceVerbose )
								Trace.WriteLine( "[V]SPLA userCrmTicket Forms Mode, IsAuthenticated true.",CRMTraceSwitch.Sw.Info);
							AddonNiceIdentity AId   =   (AddonNiceIdentity)HttpContext.Current.User.Identity;
							_userCrmTicket          =   RetrieveCrmTicket(AId.CrmImpersonateDomain,AId.CrmImpersonateLogin,AId.CrmImpersonatePwd,ref _userCrmTicketExpirationDate);
						}
						else // If we are in Forms authentication with non authenticated user, we need some default account to logon
						{
							if ( CRMTraceSwitch.Sw.TraceVerbose )
								Trace.WriteLine(
								string.Format("[V]SPLA userCrmTicket Forms Mode not authenticated getting credentials from default values to allow logon: {0}-{1}-{2}.", 
									CRMServiceDefaultAccount,CRMServiceDefaultPassword,CRMServiceDefaultDomain),CRMTraceSwitch.Sw.Info);
							// if not authenticated use default values
							_userCrmTicket          =   RetrieveCrmTicket(CRMServiceDefaultDomain,CRMServiceDefaultAccount,CRMServiceDefaultPassword,ref _userCrmTicketExpirationDate);
						}
					}
					catch (Exception ex)
					{
						if ( CRMTraceSwitch.Sw.TraceError )
							Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SPLA userCrmTicket ex: {0}", ex),CRMTraceSwitch.Sw.Info);
						throw new CRMWrapperException("CRMWrapperBase userCrmTicket ex", ex);
					}
				}
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine(string.Format("[V]SPLA userCrmTicket END ticket: '{0}'.",_userCrmTicket),CRMTraceSwitch.Sw.Info);
				return _userCrmTicket;
			}
		}

		protected string _userCrmTicketExpirationDate       =   string.Empty;
		public string userCrmTicketExpirationDate
		{
			get
			{
				return _userCrmTicketExpirationDate;
			}
		}

		public override string UrlDisco
		{
			get
			{
				return string.Format("https://{0}/mscrmservices/2007/SPLA/CrmDiscoveryService.asmx",DiscoServerName);
			}
		}

		public override CrmDiscoveryService CrmDisco
		{
			get
			{
				if (_CrmDisco == null)
				{
					_CrmDisco                           =   new CrmDiscoveryService();
					_CrmDisco.Url                       =   UrlDisco;
				}
				return _CrmDisco;
			}
		}
		
		protected string RetrieveCrmTicket(string domain,string user,string pwd,ref string ExpirationDate)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine(string.Format("[V]SPLA RetrieveCrmTicket BEG domain: {0}, user: {1}, pwd: {2}.", domain, user, pwd),CRMTraceSwitch.Sw.Info);
			RetrieveCrmTicketRequest crmTicketRequest   =   new RetrieveCrmTicketRequest();
			crmTicketRequest.OrganizationName           =   OrganizationName;
			crmTicketRequest.UserId                     =   string.Format("{0}\\{1}",domain,user);
			crmTicketRequest.Password                   =   pwd;
			RetrieveCrmTicketResponse crmTicketResponse =   (RetrieveCrmTicketResponse)CrmDisco.Execute(crmTicketRequest);
			ExpirationDate                              =   crmTicketResponse.ExpirationDate;
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine(string.Format("[V]SPLA RetrieveCrmTicket END CrmTicket: {0}, ExpirationDate: {1}.", crmTicketResponse.CrmTicket, ExpirationDate),CRMTraceSwitch.Sw.Info);
		   return crmTicketResponse.CrmTicket;
		}

		public override bool IsUserOk4Crm(string domain,string login,string pwd)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( "[V]SPLA IsUserOk4Crm BEG.",CRMTraceSwitch.Sw.Info);
			bool ret                            =   false;
			try
			{
				WhoAmIRequest request1		=   new WhoAmIRequest();
				string expdate              =   string.Empty;
				string crmticket            =   RetrieveCrmTicket(domain,login,pwd,ref expdate);
				Crm4WebService TestService	=	new Crm4WebService(ServiceUrl,false,crmticket,OrganizationName);
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA IsUserCredentialsOk Service Ok url: {0}",ServiceUrl),CRMTraceSwitch.Sw.Info);
				TestService.ExecuteRaw(request1);
				ret                         =   true;
			}
			catch (Exception ex)
			{
				string msg  =   string.Format("[E]SPLA IsUserOk4Crm ex: {0}.", ex);
				if ( CRMTraceSwitch.Sw.TraceError )
					Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
			}
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA IsUserOk4Crm END: {0}",ret),CRMTraceSwitch.Sw.Info);
			return ret;       
		}

		public override bool FindOrganization(string orgName)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA FindOrganization BEG orgName: {0}.",orgName),CRMTraceSwitch.Sw.Info);
			foreach (OrganizationDetail orgDetail in Organizations)
			{
				if ( orgDetail.OrganizationName.Equals(orgName) )
				{
					if ( CRMTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA FindOrganization found orgName: {0}, CrmServiceUrl: {1}, CrmMetadataServiceUrl: {2}.",
							orgName,orgDetail.CrmServiceUrl,orgDetail.CrmMetadataServiceUrl),CRMTraceSwitch.Sw.Info);
					Organization                                    =   orgDetail;
					OrganizationName                                =   orgDetail.OrganizationName;
					OrganizationFriendlyName                        =   orgDetail.FriendlyName;
					ServiceUrl                                      =   orgDetail.CrmServiceUrl;
					MetaDataServiceUrl                              =   orgDetail.CrmMetadataServiceUrl;
					WebApplicationUrl                               =   orgDetail.WebApplicationUrl;
					OrganizationId                                  =   orgDetail.OrganizationId;
					return true;
				}
			}
			return false;
		}
		
		/// <summary>
		/// Retrieve with disco service list of all org managed on this CRM server
		/// </summary>
		public override List<OrganizationDetail> Organizations
		{
			get
			{
				if ( (_Organizations == null) || (_Organizations.Count == 0 ))
				{
					try
					{
						_Organizations                              =   new List<OrganizationDetail>();
						RetrieveOrganizationsRequest orgRequest     =   new RetrieveOrganizationsRequest();
						orgRequest.UserId                           =   string.Format("{0}\\{1}", _CRMServiceDomain,_CRMServiceAccount);
						orgRequest.Password                         =   _CRMServicePassword;
						RetrieveOrganizationsResponse orgResponse   = (RetrieveOrganizationsResponse)CrmDisco.Execute(orgRequest);

						foreach (OrganizationDetail orgDetail in orgResponse.OrganizationDetails)
						{
							if ( CRMTraceSwitch.Sw.TraceVerbose )
								Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA Organizations GET found Organization: {0}",
									orgDetail.OrganizationName),CRMTraceSwitch.Sw.Info);
							_Organizations.Add(orgDetail);
						}
						if ( CRMTraceSwitch.Sw.TraceVerbose )
							Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA Organizations GET Count: {0}",_Organizations.Count),CRMTraceSwitch.Sw.Info);
					}
					catch (Exception ex)
					{
						string msg                                  =   string.Format("[E]SPLA Organizations GET ex: {0}", ex);
						if ( CRMTraceSwitch.Sw.TraceError )
							Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
						throw new CRMWrapperException(msg, ex);
					}
				}
				return _Organizations;
		   }
		}

		/// <summary>
		/// Called by Ctor to create Admin crmservice objects necessary to first Crm calls with admin mode
		/// </summary>
		public override void InitAdminService(bool UsePreAuthenticate)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( "[V]SPLA InitAdminService BEG.",CRMTraceSwitch.Sw.Info);
			if (_adminAdminService == null)
			{
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA InitAdminService adminAdminService START OrganizationName: {0}.",OrganizationName),CRMTraceSwitch.Sw.Info);
				try
				{
					_adminAdminService			=	new Crm4WebService(ServiceUrl,UsePreAuthenticate,adminCrmTicket,OrganizationName);
					if ( CRMTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA InitAdminService _adminAdminService Ok url: {0}",ServiceUrl),CRMTraceSwitch.Sw.Info);
				}
				catch (SoapException sx)
				{
					string msg  =   string.Format("[E]SPLA InitAdminService adminAdminService sx : {0}-{1}", sx, sx.Detail.InnerText);
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException(msg, sx);
				}
				catch (CRMWrapperException)
				{
					throw;
				}
				catch (Exception ex)
				{
					string msg  =   string.Format("[E]SPLA InitAdminService adminAdminService ex: {0}", ex);
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException(msg, ex);
				}
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]SPLA InitAdminService adminAdminService END ok",CRMTraceSwitch.Sw.Info);
			}
			if (_adminService == null)
			{
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]SPLA InitAdminService _adminService start",CRMTraceSwitch.Sw.Info);
				try
				{
					_adminService			=	adminAdminService;
					if ( CRMTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA InitAdminService _adminService.CallerIdValue : {0}", adminUserId),CRMTraceSwitch.Sw.Info);
				}
				catch (SoapException sx)
				{
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SPLA InitAdminService adminService sx : {0}-{1}", sx, sx.Detail.InnerText),CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException("adminService soap: " + sx.Detail.InnerText, sx);
				}
				catch (CRMWrapperException)
				{
					throw;
				}
				catch (Exception ex)
				{
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SPLA InitAdminService adminService ex: {0}", ex),CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException("adminService ex", ex);
				}
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]SPLA InitAdminService _adminService end",CRMTraceSwitch.Sw.Info);
			}
			if ( _adminMetaService == null )
			{
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]SPLA InitAdminService _adminMetaService start",CRMTraceSwitch.Sw.Info);
				try
				{
					_adminMetaService		        =	new Crm4MetadataWebService(MetaDataServiceUrl,true,adminCrmTicket,OrganizationName);
					if ( CRMTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( "[V]SPLA InitAdminService _adminMetaService Ok",CRMTraceSwitch.Sw.Info);
				}
				catch (SoapException sx)
				{
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SPLA InitAdminService _adminMetaService sx : {0}-{1}", sx, sx.Detail.InnerText),CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException("adminMetaService soap: " + sx.Detail.InnerText, sx);
				}
				catch (CRMWrapperException)
				{
					throw;
				}
				catch (Exception ex)
				{
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SPLA InitAdminService _adminMetaService ex: {0}", ex),CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException("adminMetaService ex", ex);
				}
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]SPLA InitAdminService _adminMetaService end",CRMTraceSwitch.Sw.Info);
			}

			// We need this to call wrapper only after Application_AuthenticateRequest has run
			// if Application_AuthenticateRequest is not runned we can get the Http.Context.Current.User and never reach this point
			 if ( CRMTraceSwitch.Sw.TraceVerbose )
				 Trace.WriteLine( "[V]SPLA InitAdminService END Ok",CRMTraceSwitch.Sw.Info);
		}
		
		/// <summary>
		/// Called by startWrapper to create different crmservice objects necessary to further running
		/// </summary>
		public override void InitServices(bool UsePreAuthenticate)
		{
			if ( CRMTraceSwitch.Sw.TraceVerbose )
				Trace.WriteLine( "[V]SPLA InitServices BEG.",CRMTraceSwitch.Sw.Info);
			if (_userService == null)
			{
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]SPLA InitServices _userService START",CRMTraceSwitch.Sw.Info);
				try
				{
					_userService				=	new Crm4WebService(ServiceUrl,UsePreAuthenticate,userCrmTicket,OrganizationName);
					if ( CRMTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA InitServices _userService Ok url: {0}",ServiceUrl),CRMTraceSwitch.Sw.Info);
				}
				catch (SoapException sx)
				{
					string msg      =   string.Format("[E]SPLA InitServices userService ex: {0}-{1}", sx, sx.Detail.InnerText);
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException(msg, sx);
				}
				catch (CRMWrapperException)
				{
					throw;
				}
				catch (Exception ex)
				{
					string msg      =   string.Format("[E]SPLA InitServices userService ex: {0}", ex);
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( msg,CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException(msg, ex);
				}
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]SPLA InitServices _userService END",CRMTraceSwitch.Sw.Info);
			}
			if (_userMetaService == null)
			{
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]SPLA InitServices _userMetaService start",CRMTraceSwitch.Sw.Info);
				try
				{
					_userMetaService		        =	new Crm4MetadataWebService(MetaDataServiceUrl,UsePreAuthenticate,userCrmTicket,OrganizationName);
					if ( CRMTraceSwitch.Sw.TraceVerbose )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SPLA InitServices _userMetaService Ok url: {0}",MetaDataServiceUrl),CRMTraceSwitch.Sw.Info);
				}
				catch (SoapException sx)
				{
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SPLA InitServices _userMetaService sx : {0}-{1}", sx, sx.Detail.InnerText),CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException("userMetaService soap: " + sx.Detail.InnerText, sx);
				}
				catch (CRMWrapperException)
				{
					throw;
				}
				catch (Exception ex)
				{
					if ( CRMTraceSwitch.Sw.TraceError )
						Trace.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SPLA InitServices _userMetaService ex: {0}", ex),CRMTraceSwitch.Sw.Info);
					throw new CRMWrapperException("userMetaService ex", ex);
				}
				if ( CRMTraceSwitch.Sw.TraceVerbose )
					Trace.WriteLine( "[V]SPLA InitServices _userMetaService end",CRMTraceSwitch.Sw.Info);
			}

			// We need this to call wrapper only after Application_AuthenticateRequest has run
			// if Application_AuthenticateRequest is not runned we can get the Http.Context.Current.User and never reach this point
			 if ( CRMTraceSwitch.Sw.TraceVerbose )
				 Trace.WriteLine( "[V]SPLA InitServices END Ok",CRMTraceSwitch.Sw.Info);
		}

		public SPLA(CrmWrapper4 wrp) : base(wrp)
		{
			 if ( CRMTraceSwitch.Sw.TraceVerbose )
				 Trace.WriteLine( "[V]SPLA Ctor Called",CRMTraceSwitch.Sw.Info);
		}
	}
}
